
/*
 页面父类基础界面
 */
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:xsdk_flutter/xsdk/framework/base/xsdk_function.dart';
import 'package:xsdk_flutter/xsdk/framework/bean/x_enum.dart';
import 'package:xsdk_flutter/xsdk/framework/support/xsdk_navigator_observers.dart';
import 'package:xsdk_flutter/xsdk/operation/x_constant_temp.dart';
import 'package:xsdk_flutter/xsdk/utils/x_utils_color.dart';
import 'package:xsdk_flutter/xsdk/utils/x_utils_dart.dart';
import 'package:xsdk_flutter/xsdk/utils/x_utils_flutter.dart';
import 'package:xsdk_flutter/xsdk/utils/x_utils_log.dart';
import 'package:xsdk_flutter/xsdk/utils/x_utils_string.dart';
import 'package:xsdk_flutter/xsdk/utils/x_utils_style.dart';
import 'package:xsdk_flutter/xsdk/utils/x_utils_widget.dart';
import 'package:xsdk_flutter/xsdk/framework/base/xsdk_widget_stateful.dart';


/*
 通用页面: XPage(()=>XStatePage());
 注意:
 1.封装时,方法不能返回XPage,而要Widget,否则无法刷新ui
 2.不能用新的XPage加载旧的XPageState,即XPageState不能单独创建为实例变量,否则会报错;
 而可以把XPage创建为实例变量,重复使用(保留状态值);


 https://blog.csdn.net/duninet/article/details/137471452
 注意:由于XWidgetUtils.getLayoutContainer()去除了key:UniqueKey(),因此要在这里默认传入UniqueKey(),保证每次都有一个唯一的标识符，防止小部件重复出现,解决XPageBottomNavigationBarCustomState的bug问题
 */
class XPage<T extends XState> extends XStatefulWidget<T> {

  XPage(
      super.createStateFunction,
      {
        super.xTag,
        super.xData
      }
      ):super(key:UniqueKey());

  //这里因XPage为通用,重写toString,改为显示具体XStatePage名称,(用于指定导航返回)//////////////////////////////////////////
  @override
  String toString({DiagnosticLevel minLevel = DiagnosticLevel.info}) {
    final String stateName = getXStateName();
    XLogUtils.printLog('---Page: $stateName');
    return stateName;

  }

  @override
  String toStringShort() {
    return toString();
  }

}


/*
通用页面实现State
注意:不能用新的XPage加载旧的XPageState,即XPageState不能单独创建为实例变量,否则会报错;
 而可以把XPage创建为实例变量,重复使用(保留状态值);
 */
abstract class XPageState extends XState<XPage> with TickerProviderStateMixin,RouteAware{

  //已自带变量widget,指向XPage

  //适用处理业务后再关闭当前页面,对应的处理方法在上一界面传入)
  XFunctionPageStateFinish? handleAndFinishPageFunction;

  //使用tabbar时,内部item可能也是xpage,那么会滑动返回时会导致多次finish,则在使用应设为false;
  bool isUsePopScopeWidget;

  //这里强制required则子类会提示生成构造方法
  XPageState(
      {
        //值true时:TabBar/BottomNavigationBar切换时,保留上次页面状态,实测:其他界面移除子widget实例变量,重新加载还是不能保存状态值;
        super.isKeepPageState=false,
        super.xTag,
        this.handleAndFinishPageFunction,
        this.isUsePopScopeWidget=true,
      }
      );

  //重写toStringShort方法,获得具体XStatePage名称
  @override
  String toStringShort() {
    return toString();
  }
  @override
  String toString({DiagnosticLevel minLevel = DiagnosticLevel.info}) {
    return XDartUtils.getRuntimeTypeName(this);
  }

  //生命周期////////////////////////////////////////////////////////


  //重写父类生命周期方法
  @override
  void initState() {
    XLogUtils.printLog('[PageState] ----- ${toString()} -----');
    super.initState();

    //用于监听当前page 离开和重新进入前台,不是内部子widget的加载或销毁监听
    _routeListener=(type, pageName) {
      //XLogUtils.printLog('---页面跳转_routeListener,type=$type,pageName=$pageName');
      if(pageName==toString()){
        if(type==1){
          onPaused();
        }else if(type==2){
          //重新设置当前page的context
          XFlutterUtils.currentContext=context;
          onResumed();
        }
      }
    };
    XSDKNavigatorObserverNotify.addRouteListener(_routeListener);
  }

  //
  late XFunctionRouteListener _routeListener;


  @override
  void onCreate() {
    /*
    (创建时)用于初始化数据,只执行一次,
    注意:不要在此获取数据,否则报错(等同不要在initState()中获取数据),如:
    final Map<String,dynamic> arguments = ModalRoute.of(context)?.settings.arguments as Map<String,dynamic>;
    double width=XFlutterUtils.getScreen();
     */

    //在开发项目中设置flutter与原生通讯通道(x_project_channel)
    if(getIsReceiveProjectNativeMessage()){
      _setReceiveProjectNativeMessageCallback();
    }
  }

  /*
  page级别重新进入前台可见(注意:第一次创建界面不会执行)
   */
  void onResumed(){

    //在开发项目中设置flutter与原生通讯通道(x_project_channel),自动重新设置恢复接收
    if(getIsReceiveProjectNativeMessage()){
      _setReceiveProjectNativeMessageCallback();
    }

  }

  /*
  page级别进入后台不可见
   */
  void onPaused(){
    //XLogUtils.printLog('[PageState] ----- ${toString()} onPaused-----');

  }

  /*
  销毁 释放资源
   */
  //ok重写集成的TickerProviderStateMixin的dispose,最后自动执行state的dispose方法
  @override
  void dispose() {
    //注意:使用TickerProviderStateMixin的controller都需要手动释放
    //XLogUtils.printLog("----dispose");
    //手动释放动画控制器,注意:要在super.dispose();前执行,否则报错!
    animationControllerMengcheng?.dispose();
    //
    super.dispose();
  }

  @override
  void onDestroy() {
    XLogUtils.printLog("---onDestroy: ${toStringShort()}");
    //
    XSDKNavigatorObserverNotify.removeRouteListener(_routeListener);

    //左右半边蒙层
    if (toStringShort()==XTempData.mengcengLeftOpenPageName){
      XTempData.isPageMengcengLeftOpen=false;
    }
    if (toStringShort()==XTempData.mengcengRightOpenPageName){
      XTempData.isPageMengcengRightOpen=false;
    }
  }

  ///////////////////////////////////////////////////////////////

  /*
  创建页面widget
  如果启用tabBar或bottomNavigation,则这里为对应各个tabOrbottomNavigationItem的内容View,
  判断各自item创建不同的widget,可以是XPage(推荐)/StatefulWidget/XStatelessWidget
  参数:
  menuItem: tabBar或者bottomNavigation的Item

  注意:如果只有1个widget,则需要使用UnconstrainedBox解除父类铺满屏幕限制,避免拉伸变形:XWidgetUtils.getLayoutUnconstrainedBox()
   */
  @required
  Widget getBodyWidget(BuildContext context);

  /*
  从界面底部弹出如输入框,是否重新改变UI布局高度
  true时, 重绘UI布局高度,则需要嵌套使用SingleChildScrollView+Column,否则UI超出可用高度,提示bottom overFlowed错误;
  如: XWidgetUtils.getLayoutSingleChildScrollView(child: _getUIWidget());
  这里默认false,弹出输入框浮在UI上,不改变原来UI布局高度,这样有可能会遮挡输入框,看情况使用不同方案;
   */
  bool getIsResizeToAvoidBottomInset(){
    if(XFlutterUtils.isAndroidOriOSSystem()){
      return XTempData.isResizeToAvoidBottomInset;
    }
    return false; //解决mac版底部无法完全恢复问题
  }

  //是否硬件按钮可返回(android侧滑边缘返回,false时禁止)
  bool getCanHardwarePressBack(){
    return true;
  }

  DateTime? currentBackPressTime;

  //是否双击退出
  bool isDoubleClickToQuit(){
    return false;
  }

  //页面背景颜色
  Color getXPageBackgroundColor(){
    return XColorUtils.pageBackgroundColor;
  }

  /*
  屏幕
  真正改变屏幕方向,XFlutterUtils.setScreenOrientation(false);如果不重新设置则后面的界面都一直沿用,因此重新进入其他界面要回复原来屏幕方向,退出该界面时则需要重写界面的finishPage添加:XFlutterUtils.setScreenOrientation(true);)
   */

  //屏幕: 旋转widget方向(类似横屏), 并没有真正改变屏幕方向,因此退出该界面后,进入其他界面还是原来的方向,注意滑动退出的手势还是竖屏时的手势)
  bool _isPortraitWidgetX=true;
  //适用:根据在构造函数中传入的值判断在oncreate中设置
  void setIsPortraitWidget(bool isPortrait){
    _isPortraitWidgetX=isPortrait;
  }
  //重写该方法,适用:直接设置该界面
  bool getIsPortraitWidget(){
    return _isPortraitWidgetX;
  }


  //开发项目是否接收原生通讯(在MainActivity中注册通道'x_project_channel')////////////////////////////////////////////////////////////
  bool getIsReceiveProjectNativeMessage(){
    return false;
  }
  final MethodChannel _methodChannel_project=const MethodChannel('x_project_channel');
  void _setReceiveProjectNativeMessageCallback(){
    if(XFlutterUtils.isAndroid()){
      XFlutterUtils.receiveNativeMessageCallback(_methodChannel_project, (resultMap){
        // String type=resultMap['type']??'';
        // if(type=='pda_scan_result'){
        //   String outputStr=resultMap['data']??'';
        //   XLogUtils.printLog('---pda_scan_result,outputStr=$outputStr');
        // }
        onReceiveProjectNativeMessageCallback(resultMap);
      });
    }
  }
  //重写处理(原生部分参考XFlutterProjectAndroidPlugin.java)
  void onReceiveProjectNativeMessageCallback(dynamic resultMap){

  }


  //页面设置//////////////////////////////////////////////////////////////////////

  /*
  状态栏
  注意:返回上一页面会沿用当前颜色,跳转新页面则不会
   */
  Color? _statusBarBackgroundColor;
  Brightness? _statusBarTextAndIconBrightness;
  void setXStatusBarColor(
      {
        Color? backgroundColor,
        bool isTextColorLight=false,
      }
      ){
    _statusBarBackgroundColor=backgroundColor;

    //状态栏,实测:android和iOS设置相反,
    if(isTextColorLight){
      //白色字体
      _statusBarTextAndIconBrightness =XFlutterUtils.isiOS()?Brightness.dark:Brightness.light;
    }else{
      //黑色字体
      _statusBarTextAndIconBrightness =XFlutterUtils.isiOS()?Brightness.light:Brightness.dark;

    }

  }

  //标题栏/////////////////////////////////////////////////////

  //是否显示标题栏
  bool _isShowTitleBar=false;
  //是否显示左按钮图标
  bool _isShowTitleBarLeftWidget=false;
  //是否底部分割线
  bool _isShowTitleBarBottomDivider=true;
  //标题是否居中
  bool _isShowTitleBarTitleTextCenter=true;
  //居中标题
  String? _titleBarCenterText;
  String? _titleBarCenterSubText;//副标题
  //标题栏背景
  Color? _titleBarBackgroundColor;
  //标题栏分割线颜色
  Color? _titleBarDividerColor;
  Color? _titleBarTitleTextColor;
  Color? _titleBarSubTitleTextColor;
  Color? _titleBarLeftWidgetColor;
  //标题栏默认左按钮
  Widget? _titleBarLeftWidget;
  //标题栏右按钮
  List<Widget>? _titleBarRightWidgets;
  //标题栏高度
  double? _titleBarHeight;
  //自定义leftWidget过长时需要设置的宽度
  double? _titleBarLeftLeadingWidth;

  //设置标题栏
  void setXTitle(
      {
        bool isShowTitleBar=true,//是否标题栏
        double? titleBarHeight=48,//高度
        String ?titleText,
        String ?subTitleText,
        bool isShowTitleTextCenter=true,//标题是否居中
        Color? backgroundColor=const Color(0xFFFFFFFF),//标题栏背景颜色
        Color? titleBarDividerColor,//标题栏分割线颜色
        Color? titleBarTitleTextColor,//
        Color? titleBarSubTitleTextColor,//
        Color? titleBarLeftWidgetColor,//
        bool isShowBottomDivider=false,//是否显示底部分割线
        bool isShowLeftWidget=true,//是否显示左按钮图标
        Widget? leftWidget,//更新左按钮图标(更新替代)
        double? titleBarLeftLeadingWidth, ////自定义leftWidget过长时需要设置
        List<Widget>? rightWidgets,
      }
      ){
    _isShowTitleBar=isShowTitleBar;
    _titleBarCenterText=titleText;
    _titleBarCenterSubText=subTitleText;
    _isShowTitleBarBottomDivider=isShowBottomDivider;
    _titleBarBackgroundColor=backgroundColor;
    _isShowTitleBarTitleTextCenter=isShowTitleTextCenter;
    _titleBarHeight=titleBarHeight;
    _titleBarDividerColor=titleBarDividerColor??XColorUtils.dividerColor;
    _titleBarTitleTextColor=titleBarTitleTextColor;
    _titleBarSubTitleTextColor=titleBarSubTitleTextColor;
    _titleBarLeftWidgetColor=titleBarLeftWidgetColor;
    _titleBarLeftLeadingWidth=titleBarLeftLeadingWidth;

    //左按钮图标
    _isShowTitleBarLeftWidget=isShowLeftWidget;
    _titleBarLeftWidget=leftWidget;

    //右按钮图标
    _titleBarRightWidgets=rightWidgets;

  }


  //页面中间主体部分浮层空间 ////////////////////////////////////////////////////////
  Widget? _page_stack_top_index_widget;
  void setXStackPageTopIndexWidget(
      Widget? widget
      ){
    //可用Positioned等
    _page_stack_top_index_widget=widget;

  }


  //页面中间主体部分上下空间 ////////////////////////////////////////////////////////
  Widget? _page_topbar_widget;
  Widget? _page_topbar_widget2;
  Widget? _page_bottombar_widget;

  void setXTopBarWidget(
      {
        required Widget? child,
        double? height=48,
        Color? backgroundColor,
        EdgeInsets? margin,//getEdgeInsets(left,top,right,bottom)
        EdgeInsets? padding,//getEdgeInsets(left,top,right,bottom)
        bool isShowBottomDivider=false,
        Alignment? alignment,//对齐,注意:当为null时,子控件的Container大小设置无效,自动按父Container的大小铺满, 如果不为null,则按子Container实际大小
      }
      ){

    if(child==null){
      _page_topbar_widget=null;
    }else{

      if(height!=null && height<=0){
        height=null;
      }
      if(height==null){
        alignment ??= Alignment.topLeft;
      }

      _page_topbar_widget=XWidgetUtils.getLayoutContainer(
        width: double.infinity,
        height: height,
        alignment:alignment,
        backgroundColor: backgroundColor,
        margin:margin,
        padding:padding,
        child: child,
        decoration: isShowBottomDivider?XWidgetUtils.getBoxDecoration(
          border:Border(
              bottom: BorderSide(
                  color: XColorUtils.dividerColor,
                  width: XTempData.defaultDividerHeight
              )
          ),
          backgroundColor: backgroundColor,
        ):null,

      );
    }
  }

  void setXTopBarWidget2(
      {
        required Widget? child,
        double? height=48,
        Color? backgroundColor,
        EdgeInsets? margin,//getEdgeInsets(left,top,right,bottom)
        EdgeInsets? padding,//getEdgeInsets(left,top,right,bottom)
        bool isShowBottomDivider=false,
        Alignment? alignment,//对齐,注意:当为null时,子控件的Container大小设置无效,自动按父Container的大小铺满, 如果不为null,则按子Container实际大小
      }
      ){

    if(child==null){
      _page_topbar_widget2=null;
    }else{

      if(height!=null && height<=0){
        height=null;
      }
      if(height==null){
        alignment ??= Alignment.topLeft;
      }

      _page_topbar_widget2=XWidgetUtils.getLayoutContainer(
        width: double.infinity,
        height: height,
        alignment:alignment,
        backgroundColor: backgroundColor,
        margin:margin,
        padding:padding,
        child: child,
        decoration: isShowBottomDivider?XWidgetUtils.getBoxDecoration(
          border:Border(
              bottom: BorderSide(
                  color: XColorUtils.dividerColor,
                  width: XTempData.defaultDividerHeight
              )
          ),
          backgroundColor: backgroundColor,
        ):null,
      );
    }
  }

  void setXBottomBarWidget(
      {
        required Widget? child,
        double? height,
        Color? backgroundColor,
        EdgeInsets? margin,//getEdgeInsets(left,top,right,bottom)
        EdgeInsets? padding,//getEdgeInsets(left,top,right,bottom)
        Alignment? alignment,//对齐,注意:当为null时,子控件的Container大小设置无效,自动按父Container的大小铺满, 如果不为null,则按子Container实际大小
      }
      ){

    if(child==null){
      _page_bottombar_widget=null;
    }else{

      height ??= XWidgetUtils.getBottomBarHeight();
      if(height<=0){
        height=null;
        alignment ??= Alignment.topLeft;
      }

      _page_bottombar_widget=XWidgetUtils.getLayoutContainer(
        width: double.infinity,
        height: height,
        backgroundColor: backgroundColor,
        margin:margin,
        padding:padding,
        alignment: alignment,
        child: child,
      );

    }

  }

  //页面左右两边空间 ////////////////////////////////////////////////////////
  Widget? _page_left_space;
  Widget? _page_right_space;
  //左右蒙层自身动画
  AnimationController? animationControllerMengcheng;
  CurvedAnimation? _curvedAnimationMengcheng;

  void setXLeftFixSpace(
      {
        double? width,
        Widget? replaceWidget,
        void Function()? replaceDefaultOnTap,
      }
      ){
    if(replaceWidget==null){
      //默认空白半透明

      //蒙层颜色(默认透明,多层时避免加深)
      Color mengcengColor=Colors.transparent;
      if (!XTempData.isPageMengcengLeftOpen){
        XTempData.isPageMengcengLeftOpen=true;
        mengcengColor=XColorUtils.pageMengcengColor;
        XTempData.mengcengLeftOpenPageName=toStringShort();
      }

      //itemWidget实现动画
      animationControllerMengcheng??= AnimationController(
        duration: const Duration(milliseconds: 500),
        reverseDuration: const Duration(milliseconds: 50),
        vsync: this,
      );
      _curvedAnimationMengcheng??= CurvedAnimation(parent: animationControllerMengcheng!, curve: Curves.easeIn);
      // bounceIn = CurvedAnimation(parent: controller, curve: Curves.bounceIn);
      // linear = CurvedAnimation(parent: controller, curve: Curves.linear);
      // decelerate = CurvedAnimation(parent: controller, curve: Curves.decelerate);
      // 也可使用简单的: Tween(begin: 50.0, end: 120.0).animate(animationController500);

      // curvedAnimation.addStatusListener((status) {
      //   if (status == AnimationStatus.completed) {
      //     _animationControllerMengcheng?.reverse();
      //   } else if (status == AnimationStatus.dismissed) {
      //     _animationControllerMengcheng?.forward();
      //   }
      // });

      _page_left_space=FadeTransition(
        opacity: _curvedAnimationMengcheng!,
        child: XWidgetUtils.getLayoutColumn(
            children:[
              XWidgetUtils.getLayoutExpanded(
                  XWidgetUtils.getLayoutContainer(
                      width: width,
                      backgroundColor: mengcengColor,
                      child:XWidgetUtils.getWidgetGestureDetector(
                          onTap: replaceDefaultOnTap??(){
                            finishPage();
                          }
                      )
                  )
              )
            ]),
      );

      //蒙版动画正方向执行
      animationControllerMengcheng?.forward();

    }else{
      //替代layout widget
      //_page_left_space=replaceWidget; //这样会itemWidget超出范围报错
      _page_left_space=XWidgetUtils.getLayoutColumn(
          children:[
            XWidgetUtils.getLayoutExpanded(
                XWidgetUtils.getLayoutContainer(
                    width: width,
                    child:replaceWidget
                )
            )
          ]
      );
    }
  }
  void setXRightFixSpace(
      {
        double? width,
        Widget? replaceWidget,
        void Function()? replaceDefaultOnTap,
      }
      ){
    if(replaceWidget==null){
//默认空白半透明

//蒙层颜色(默认透明,多层时避免加深)
      Color mengcengColor=Colors.transparent;
      if (!XTempData.isPageMengcengRightOpen){
        XTempData.isPageMengcengRightOpen=true;
        mengcengColor=XColorUtils.pageMengcengColor;
        XTempData.mengcengRightOpenPageName=toStringShort();
      }

//itemWidget实现动画
      animationControllerMengcheng??= AnimationController(
        duration: const Duration(milliseconds: 500),
        reverseDuration: const Duration(milliseconds: 50),
        vsync: this,
      );
      _curvedAnimationMengcheng??= CurvedAnimation(parent: animationControllerMengcheng!, curve: Curves.easeIn);
// bounceIn = CurvedAnimation(parent: controller, curve: Curves.bounceIn);
// linear = CurvedAnimation(parent: controller, curve: Curves.linear);
// decelerate = CurvedAnimation(parent: controller, curve: Curves.decelerate);
// 也可使用简单的: Tween(begin: 50.0, end: 120.0).animate(animationController500);

      _page_right_space=FadeTransition(
        opacity: _curvedAnimationMengcheng!,
        child: XWidgetUtils.getLayoutColumn(
            children:[
              XWidgetUtils.getLayoutExpanded(
                  XWidgetUtils.getLayoutContainer(
                      width: width,
                      backgroundColor: mengcengColor,
                      child:XWidgetUtils.getWidgetGestureDetector(
                          onTap: replaceDefaultOnTap??(){
                            finishPage();
                          }
                      )
                  )
              )
            ]),
      );
    }else{
//替代layout widget
//_page_right_space=replaceWidget; //这样会itemWidget超出范围报错
      _page_right_space=XWidgetUtils.getLayoutColumn(
          children:[
            XWidgetUtils.getLayoutExpanded(
                XWidgetUtils.getLayoutContainer(
                    width: width,
                    child:replaceWidget
                )
            )
          ]
      );

    }
  }

//////////////////////////////////////////////////////////////////////////////////////////


//构建页面
  @override
  Widget onBuild(BuildContext context) {
    try {
      //已自带context变量
      //xContext=context;

      //页面左中右结构
      List<Widget> pageRowLayout = [];
      //页面左结构部分
      if (_page_left_space != null) {
        pageRowLayout.add(_page_left_space!);
      }
      //页面中间结构部分
      pageRowLayout.add(_createPageCenterWidget(context));
      //页面右结构部分
      if (_page_right_space != null) {
        pageRowLayout.add(_page_right_space!);
      }

      //主体
      Widget mainXWidget=XWidgetUtils.getLayoutRow(
          crossAxisAlignment:CrossAxisAlignment.start,
          children:pageRowLayout
      );

      //默认竖屏 注意:Transform.rotate(angle: pi / 2,child: ..)原来的长宽不变, 而RotatedBox原来的长宽对调
      Widget pWidget=getIsPortraitWidget()? mainXWidget
          : RotatedBox(
        quarterTurns: 1,//这里屏幕方向不变, widget旋转90度(模拟横向,退出该界面,其他界面恢复原来;
        child: XWidgetUtils.getLayoutContainer(
          //空出左边为原来状态栏的高度(默认存在竖屏状态栏)
          padding: XWidgetUtils.getEdgeInsets(XTempData.statusBarHeight, 0, 0, 0),
          child: mainXWidget,
        ),
      );

      //Material是一种标准的移动端和web端的视觉设计语言。 Flutter提供了一套丰富的Material widgets。需要位于MaterialApp内才能正常显示
      return Material(
        //Material背景透明
        color: Colors.transparent,
        //PopScope 替代WillPopScope,注意使用tabbar时,内部item可能也是xpage,那么会滑动返回时会导致多次finish,则在使用应设为false;
        //当canPop为true，则系统返回手势将导致封闭的 Navigator 照常接收弹出。会调用 onPopInvoked，此时didPop为true。
        //当canPop为false，则系统返回手势不会将路由从封闭的 Navigator 中弹出，但仍然会调用onPopInvoked方法，此时didPop为false，此时进行逻辑判断或者插入其他需要执行的代码，如果需要返回则再执行Navigator.of(context).pop(); 注意此时onPopInvoked又会被再次调用，但此时didPop为true。因此，在onPopInvoked中，需要判断一下 didPop，如果为 true, 则 return。
        child: isUsePopScopeWidget?PopScope(
          canPop: false,//注意:这里统一设置false值,滑动返回时,onPopInvoked第一次不走true,返回false时拦截可以自定义执行finishPage()
          onPopInvoked: (bool didPop){
            //XLogUtils.printLog('---didPop=$didPop');
            if(didPop){
              //finishPage(); 注意:这里不能拦截执行自定义finishPage()返回,会造成重复返回,底层报错!
              return;
            }else{
              //当canPop:false时,滑动返回也会激活此回调,注意:这里可以拦截自定义执行finishPage()返回
              if(_scopePop()){
                if(isDoubleClickToQuit()){
                  XFlutterUtils.closeApp();
                }else{
                  finishPage();
                }
              }

            }
          },
          child: pWidget,
        ):pWidget,
        //左中右结构
      );

    }catch(error, stacktrace){
      //第一个参数 error 类型为 Object，也就是异常是可以抛出任意对象。
      //第二个参数 stacktrace，表示异常堆栈。
      XLogUtils.printLog('异常: $error');
      XLogUtils.printLog('异常: $stacktrace');
      return XWidgetUtils.getWidgetText('Widget build异常: $error');
    }

  }

  //android滑动返回,物理键返回监听
  bool _scopePop(){

    if(getCanHardwarePressBack()){

      if(isDoubleClickToQuit()){
        // 检查是否已经点击过一次返回按钮
        if (currentBackPressTime == null ||
            DateTime.now().difference(currentBackPressTime!) > const Duration(seconds: 2)) {
          // 如果没有点击过或已经过了 2 秒，则记录当前时间，并显示提示信息
          currentBackPressTime = DateTime.now();
          toast('再按一次返回键退出');
          return false;
        }

        return isDoubleClickToQuit();
      }
    }



    // 如果连续两次点击间隔小于 2 秒，则退出应用程序
    return getCanHardwarePressBack();


  }

//私有方法////////////////////////////////////////////////////////////////////////////

/*
  Scaffold创建页面中间部分Widget(页面结构左中右)

  设置悬浮按钮显示的位置
FloatingActionButtonLocation.startTop,FloatingActionButtonLocation.miniStartTop 显示在左上角
FloatingActionButtonLocation.endFloat 默认使用 浮动右下角,显示在右下角但是离底部有距离,
FloatingActionButtonLocation.endDocked 显示在右下角紧挨着底部
FloatingActionButtonLocation.centerFloat 底部中间浮动,显示在底部中间但是离底部有距离
FloatingActionButtonLocation.centerDocked 底部中间不浮动,显示在底部中间紧挨着底部
FloatingActionButtonLocation.endTop 显示在右上角
   */
  Widget _createPageCenterWidget(BuildContext context){
    //外层Row,中间部分占满屏幕剩余空间,如果内部itemlayout不重新使用row或Column,使用UnconstrainedBox去掉父类约束,则默认都会占满可用空间(设置width固定大小无效)

    return XWidgetUtils.getLayoutExpanded(
        getIsPortraitWidget()?_createPageMainScaffold(context)
        //旋转widget(类似横屏后)后,适配iOS的Scaffold会把顶部statusBar高度预留出来,不能点击顶部区域
            :MediaQuery.removePadding(
            context: context,
            removeTop: true,
            child:_createPageMainScaffold(context)
        )
    );
  }

  Widget _createPageMainScaffold(BuildContext context){
    // Scaffold 是 Material library 中提供的一个widget, 它提供了默认的导航栏、标题和包含主屏幕widget树的body属性。
    //使用Scaffold是最容易的，它提供了一个默认banner，背景颜色，并且具有添加drawer，snack bar和底部sheet的API
    return Scaffold(
      //标题栏

      appBar: !_isShowTitleBar ? null : _createAppBar(),
      //primary: true,是否在屏幕顶部显示Appbar, 默认为 true
      //底部栏
      bottomNavigationBar: createBottomNavigationBar(),
      persistentFooterButtons:null,//在底部导航条bottomNavigationBar上方显示一组按钮
      bottomSheet:null,//底部弹出半屏控件,会在底部导航条bottomNavigationBar上方,BottomSheet
      //左右侧栏
      drawer: !_isEnableDrawer?null:_createDrawer(),
      endDrawer: !_isEnableEndDrawer?null:_createEndDrawer(),
      drawerEdgeDragWidth: 25,//设置可拖拽区域宽度，在区域内才能拖拽出抽屉
      drawerEnableOpenDragGesture: _isEnableDrawer?true:false,//左侧侧滑栏是否可以滑动
      endDrawerEnableOpenDragGesture:_isEnableEndDrawer?true:false,//右侧侧滑栏是否可以滑动
      drawerScrimColor: XColorUtils.pageMengcengColor,//左右侧栏蒙层颜色,null时为默认半透明
      //drawerDragStartBehavior: DragStartBehavior.start,//处理拖动行为的开始方式，默认是DragStartBehavior.start
      //悬浮按钮
      floatingActionButton: _floatingActionButton,//FloatingActionButton
      floatingActionButtonLocation:_floatingActionButtonLocation,//悬浮按钮位置
      floatingActionButtonAnimator:FloatingActionButtonAnimator.scaling,//悬浮按钮动画
      //主体body,使用Builder来包装获得Scaffold的context
      body: Builder(builder:(BuildContext context){
        contextOfScaffold=context;
        XFlutterUtils.currentContext=context;

        return _createStackWidget(context);
      }),
      //extendBody: false,//默认false,如果为true则[body主体]延伸到脚手架的屏幕底部,不是只扩展到[bottomNavigationBar和persistentFooterButtons]的顶部
      //extendBodyBehindAppBar: false, //默认false, 如果为true时，则body会置顶到屏幕顶, 那么appbar会覆盖在body上，如appbar 为半透明色，可以有毛玻璃效果
      //resizeToAvoidBottomInset: true,//默认true,设置键盘弹起时是否会遮挡底部的布局，false则会进行遮挡，true则不会进行遮挡。
      resizeToAvoidBottomInset: getIsResizeToAvoidBottomInset(),
      backgroundColor: getXPageBackgroundColor(), //Colors.transparent,//Scaffold背景色(页面)
    );
  }

  //设置悬浮按钮,注意:可用setXStackPageTopIndexWidget替代,自定义位置
  FloatingActionButton? _floatingActionButton;
  FloatingActionButtonLocation? _floatingActionButtonLocation;
  void setXFloatingActionButton(
      FloatingActionButton? floatingActionButton,
      {FloatingActionButtonLocation floatingActionButtonLocation=FloatingActionButtonLocation.miniEndFloat}
      ){
    _floatingActionButtonLocation=floatingActionButtonLocation;
    _floatingActionButton=floatingActionButton;
  }

  //监听键盘回调(重写)
  void onKeyboardListener(KeyEvent key){

  }

//Drawer, EndDrawer////////////////////////////////////////////////////////////////////////////

//是否启用左侧栏
  bool _isEnableDrawer=false;
//左侧栏宽度
  double _drawerWidth=150;
//左侧栏背景颜色
  Color? _drawerBackgroundColor;
  Widget? _leftDrawer;
  void setXDrawer(
      Widget leftDrawer,
      {
        bool isEnableDrawer=true,
        Color? backgroundColor,
        double width=150,
      }
      ){

    _isEnableDrawer=isEnableDrawer;
    _drawerBackgroundColor=backgroundColor;
    _drawerWidth=width;
    _leftDrawer=leftDrawer;
  }

//是否启用右侧栏
  bool _isEnableEndDrawer=false;
//左侧栏宽度
  double _endDrawerWidth=150;
//左侧栏背景颜色
  Color? _endDrawerBackgroundColor;
  Widget? _rightDrawer;
  void setXEndDrawer(
      Widget rightDrawer,
      {
        bool isEnableEndDrawer=true,
        Color? backgroundColor,
        double width=150,
      }
      ){

    _isEnableEndDrawer=isEnableEndDrawer;
    _endDrawerBackgroundColor=backgroundColor;
    _endDrawerWidth=width;
    _rightDrawer=rightDrawer;
  }


//使用Builder来包装获得Scaffold的context
  BuildContext? contextOfScaffold;
  void openDrawer(){
    if(contextOfScaffold!=null){
      XFlutterUtils.openDrawer(contextOfScaffold!);
    }
  }
  void closeDrawer(){
    if(contextOfScaffold!=null){
      XFlutterUtils.closeDrawer(contextOfScaffold!);
    }
  }
  void openEndDrawer(){
    if(contextOfScaffold!=null){
      XFlutterUtils.openEndDrawer(contextOfScaffold!);
    }
  }
  void closeEndDrawer(){
    if(contextOfScaffold!=null){
      XFlutterUtils.closeEndDrawer(contextOfScaffold!);
    }
  }


//左侧栏
  Drawer _createDrawer(){
    return Drawer(
      backgroundColor: _drawerBackgroundColor,
      width: _drawerWidth,
      child: _leftDrawer,
    );
  }

//右侧栏
  Drawer _createEndDrawer(){
    return Drawer(
      backgroundColor: _drawerBackgroundColor,
      width: _drawerWidth,
      child: _leftDrawer,
    );
  }


//创建标题栏
  AppBar _createAppBar(){
    return AppBar(
      //分割线阴影颜色
      shadowColor: _titleBarDividerColor,
      //影深(标题栏分割线阴影高度)
      elevation: _isShowTitleBarBottomDivider ? 0.5 : 0,
      scrolledUnderElevation: _isShowTitleBarBottomDivider ? 0.5 : 0,//防止listview滚动改变appBar的颜色
      //背景颜色
      backgroundColor: _titleBarBackgroundColor,
      //foregroundColor: _titleBarBackgroundColor,
      surfaceTintColor: _titleBarBackgroundColor,//防止listview可滚动时提示颜色
      toolbarHeight: _titleBarHeight,
      //状态栏(不设置则已全局为准)
      systemOverlayStyle: _statusBarTextAndIconBrightness==null?null:SystemUiOverlayStyle(
          statusBarColor: _statusBarBackgroundColor ?? Colors.transparent,
          statusBarBrightness: _statusBarTextAndIconBrightness,
          statusBarIconBrightness: _statusBarTextAndIconBrightness
      ),
      //标题文字
      title: XStringUtils.isEmpty(_titleBarCenterSubText)?XWidgetUtils.getWidgetText(
        _titleBarCenterText ?? '',
        style: TextStyle(
          color: _titleBarTitleTextColor?? const Color(0xFF333333),
          fontSize: 16,
          fontWeight: FontWeight.bold,
        ),
      ):XWidgetUtils.getLayoutColumn(
          mainAxisSize:MainAxisSize.min,
          mainAxisAlignment:MainAxisAlignment.center,
          crossAxisAlignment:_isShowTitleBarTitleTextCenter?CrossAxisAlignment.center:CrossAxisAlignment.start,
          children: [
            XWidgetUtils.getWidgetText(
                _titleBarCenterText ?? '',
                style: XStyleUtils.getTextStyle(
                    fontSize: 16,
                    color: _titleBarTitleTextColor?? const Color(0xFF333333),
                    fontWeight: FontWeight.bold
                )
            ),
            XWidgetUtils.getWidgetText(
              _titleBarCenterSubText ?? '',
              style: XStyleUtils.getTextStyle(
                fontSize: 11,
                color: _titleBarSubTitleTextColor?? const Color(0xFF666666),
              ),
            )
          ]
      ),
      //标题居中显示
      centerTitle: _isShowTitleBarTitleTextCenter,
      //支持tabBar(判断是否在appBar中)
      // bottom: PreferredSize(
      //   preferredSize: Size.fromHeight(_tabBarHeight),
      //   child: XWidgetUtils.getLayoutContainer(
      //     //是否居中显示,否则靠左
      //     child: ,
      //     backgroundColor: _tabBarBackgroundColor,
      //     height: _tabBarHeight,
      //     width: double.infinity,
      //   ), //创建tabBar
      // ),//bottom
      leadingWidth: _titleBarLeftLeadingWidth, //自定义leftWidget过长时需要设置,
      leading: !_isShowTitleBarLeftWidget
          ? XWidgetUtils.getLayoutContainer()
          : _titleBarLeftWidget ?? IconButton(
        icon: Icon(
          Icons.arrow_back_ios_new_rounded,
          color: _titleBarLeftWidgetColor?? const Color(0xFF333333),
        ),
        onPressed: () {
          //返回上一页
          titleBarLeftWidgetOnPressed();
        },
      ),
      //左边按钮Widget, ImageIcon()
      actions: _titleBarRightWidgets, //右边按钮Widget
    );
  }

  //标题头左侧返回点击方法(可重写)
  void titleBarLeftWidgetOnPressed(){
    finishPage();
  }

//创建Scaffold的body,浮层
  Widget _createStackWidget(BuildContext context){

    //页面浮层结构
    List<Widget> stackLayout = [];
    stackLayout.add(_createScaffoldBodyWidget(context));

    //stack item 在最上层
    if (_page_stack_top_index_widget != null) {
      stackLayout.add(_page_stack_top_index_widget!);
    }

    return XWidgetUtils.getLayoutStack(children:stackLayout);
  }

//创建Scaffold的body,支持tabBar/bottomNavigationBar,支持自定义topBar和bottomBar
  Widget _createScaffoldBodyWidget(BuildContext context){

    //页面上中下结构
    List<Widget> columnLayout = [];

    //topBar
    if (_page_topbar_widget != null) {
      columnLayout.add(_page_topbar_widget!);
    }
    if (_page_topbar_widget2 != null) {
      columnLayout.add(_page_topbar_widget2!);
    }

    Widget? bottomNavigationBarView=createBottomNavigationBarView();
    if(bottomNavigationBarView!=null){
      //启用BottomNavigationBar
      columnLayout.add(XWidgetUtils.getLayoutExpanded(bottomNavigationBarView));
    }else{
      //没有启用TabBar和BottomNavigationBar
      if(getIsBodyWidgetExpanded()){
        //getBodyWidget铺满剩余屏幕大小
        columnLayout.add(XWidgetUtils.getLayoutExpanded(getBodyWidget(context)));
      }else{
        //getBodyWidget不铺满,按自己大小
        columnLayout.add(getBodyWidget(context));
        columnLayout.add(const Spacer());
      }

    }

    //bottomBar
    if (_page_bottombar_widget != null) {
      columnLayout.add(_page_bottombar_widget!);
    }

    return XWidgetUtils.getLayoutColumn(children:columnLayout);

  }


  //BodyWidget默认是否铺满剩余屏幕,还是按自己大小
  bool getIsBodyWidgetExpanded(){
    return true;
  }

//跳转页面////////////////////////////////////////////////////////////////////////

//获得上一界面传递的数据(RouteSettings.arguments)
  dynamic getPrePageDataFromRouteSettings(){
    //final Map<String,dynamic> arguments = ModalRoute.of(context)?.settings.arguments as Map<String,dynamic>;
    return XFlutterUtils.getPrePageDataFromRouteSettings(context);
  }


//跳转页面
  void startPage(
      //Widget
      XPageState pageState,
      {
        XPageCallback? resultCallback, //传入等待数据返回进一步处理,则传入响应方法(result){...}
        //跳转后是否关闭当前页
        bool isFinish=false,
        dynamic data,//传递到下一页的数据,获取final Map<String,dynamic> arguments = ModalRoute.of(context)?.settings.arguments as Map<String,dynamic>;
        XAnimationType pageAnimationType=XAnimationType.custom,//跳转页面动画
        String? cleanUntilRetainPageName,
      }
      ){

    XFlutterUtils.startPage(
      context,
      XPage(()=>pageState),
      resultCallback:resultCallback,
      isFinish:isFinish,
      data:data,
      pageAnimationType:pageAnimationType,
      cleanUntilRetainPageName:cleanUntilRetainPageName,
    );
  }

  /*
  返回上一页
  如果弹出半屏或其他弹框,第一返回只关闭半屏或弹框,则再次判断是否挂载调用多一次关闭,如:
  finish();
  if(mounted){
     finishPage();
  }
  也可使用backToPointPageName替代(指定前一页)
   */
  void finishPage(
      {
        dynamic result,
        String? backToPointPageName,//指定返回界面:   返回首页'/'
      }
      ) {

    //蒙层动画正方向运行
    //_animationControllerMengcheng?.forward();
    //蒙层动画反方向运行
    animationControllerMengcheng?.reverse();

    //
    XFlutterUtils.finishPage(context,result: result, backToPointPageName: backToPointPageName);
  }


  //处理业务后再关闭(执行上一页面传入的处理方法)
  void finishAfterHandleFunction(dynamic result){
    if(handleAndFinishPageFunction!=null){
      handleAndFinishPageFunction!(result,finishPage);
    }else{
      finishPage(result:result);
    }
  }

  //创建内置BottomNavigationBar(在XPageBottomNavigationBarState重写使用)
  Widget? createBottomNavigationBar(){
    return null;
  }

  //创建内置BottomNavigationBarView(在XPageBottomNavigationBarState重写使用)
  Widget? createBottomNavigationBarView(){
    return null;
  }

}